#include "sdk.h"
#include <wx/app.h>
#include <wx/toolbar.h>
#include <wx/fs_mem.h>
#include "M_Code_colourmanager.h"
#include "ccmanager.h"
#include "debuggermanager.h"

static Manager* s_ManagerInstance = nullptr;
bool Manager::m_AppShuttingDown = false;
bool Manager::m_AppStartedUp = false;
bool Manager::m_BlockYields = false;
bool Manager::m_IsBatch = false;
wxCmdLineParser Manager::m_CmdLineParser;

Manager::Manager() : m_pAppWindow( nullptr ), m_SearchResultLog( nullptr ) {
}

Manager::~Manager() {
  for( EventSinksMap::iterator mit = m_EventSinks.begin(); mit != m_EventSinks.end(); ++mit ) {
    while( mit->second.size() ) {
      delete( *( mit->second.begin() ) );
      mit->second.erase( mit->second.begin() );
    }
  }
  for( DockEventSinksMap::iterator mit = m_DockEventSinks.begin(); mit != m_DockEventSinks.end(); ++mit ) {
    while( mit->second.size() ) {
      delete( *( mit->second.begin() ) );
      mit->second.erase( mit->second.begin() );
    }
  }
  for( LayoutEventSinksMap::iterator mit = m_LayoutEventSinks.begin(); mit != m_LayoutEventSinks.end(); ++mit ) {
    while( mit->second.size() ) {
      delete( *( mit->second.begin() ) );
      mit->second.erase( mit->second.begin() );
    }
  }
  for( LogEventSinksMap::iterator mit = m_LogEventSinks.begin(); mit != m_LogEventSinks.end(); ++mit ) {
    while( mit->second.size() ) {
      delete( *( mit->second.begin() ) );
      mit->second.erase( mit->second.begin() );
    }
  }
}

Manager* Manager::Get( wxFrame *appWindow ) {
  if( appWindow ) {
    if( Get()->m_pAppWindow ) {
      Get()->GetLogManager()->LogInf( _T( "Illegal argument to Manager::Get()" ) );
    } else {
      Get()->m_pAppWindow = appWindow;
      Get()->GetLogManager()->LogInf( _T( "加载管理器资源" ) );
    }
  }
  return Get();
}

Manager* Manager::Get() {
  if( !s_ManagerInstance ) {
    s_ManagerInstance = new Manager;
  }
  return s_ManagerInstance;
}

void Manager::Free() {
  delete s_ManagerInstance;
  s_ManagerInstance = nullptr;
}

void Manager::SetAppStartedUp( bool app_started_up ) {
  m_AppStartedUp = app_started_up;
}

void Manager::SetAppShuttingDown( bool app_shutting_down ) {
  m_AppShuttingDown = app_shutting_down;
}

void Manager::SetBatchBuild( bool is_batch ) {
  m_IsBatch = is_batch;
}

void Manager::BlockYields( bool block ) {
  m_BlockYields = block;
}

void Manager::ProcessPendingEvents() {
  if( !m_BlockYields && !m_AppShuttingDown ) {
    wxTheApp->ProcessPendingEvents();
  }
}

void Manager::Yield() {
  if( !m_BlockYields && !m_AppShuttingDown ) {
    wxTheApp->Yield( true );
  }
}

void Manager::Shutdown() {
  m_AppShuttingDown = true;
  ToolsManager::Free();
  TemplateManager::Free();
  CCManager::Free();
  PluginManager::Free();
  DebuggerManager::Free();
  ScriptingManager::Free();
  ProjectManager::Free();
  EditorManager::Free();
  PersonalityManager::Free();
  MacrosManager::Free();
  UserVariableManager::Free();
  LogManager::Free();
  CfgMgrBldr::Free();
}

bool Manager::ProcessEvent( CodeBlocksEvent& event ) {
  if( IsAppShuttingDown() ) {
    return false;
  }
  EventSinksMap::iterator mit = m_EventSinks.find( event.GetEventType() );
  if( mit != m_EventSinks.end() ) {
    for( EventSinksArray::iterator it = mit->second.begin(); it != mit->second.end(); ++it ) {
      ( *it )->Call( event );
    }
  }
  return true;
}

bool Manager::ProcessEvent( CodeBlocksDockEvent& event ) {
  if( IsAppShuttingDown() ) {
    return false;
  }
  DockEventSinksMap::iterator mit = m_DockEventSinks.find( event.GetEventType() );
  if( mit != m_DockEventSinks.end() ) {
    for( DockEventSinksArray::iterator it = mit->second.begin(); it != mit->second.end(); ++it ) {
      ( *it )->Call( event );
    }
  }
  return true;
}

bool Manager::ProcessEvent( CodeBlocksLayoutEvent& event ) {
  if( IsAppShuttingDown() ) {
    return false;
  }
  LayoutEventSinksMap::iterator mit = m_LayoutEventSinks.find( event.GetEventType() );
  if( mit != m_LayoutEventSinks.end() ) {
    for( LayoutEventSinksArray::iterator it = mit->second.begin(); it != mit->second.end(); ++it ) {
      ( *it )->Call( event );
    }
  }
  return true;
}

bool Manager::ProcessEvent( CodeBlocksLogEvent& event ) {
  if( IsAppShuttingDown() ) {
    return false;
  }
  LogEventSinksMap::iterator mit = m_LogEventSinks.find( event.GetEventType() );
  if( mit != m_LogEventSinks.end() ) {
    for( LogEventSinksArray::iterator it = mit->second.begin(); it != mit->second.end(); ++it ) {
      ( *it )->Call( event );
    }
  }
  return true;
}

bool Manager::IsAppShuttingDown() {
  return m_AppShuttingDown;
}

bool Manager::IsAppStartedUp() {
  return m_AppStartedUp;
}

void Manager::InitXRC( bool force ) {
  static bool xrcok = false;
  if( !xrcok || force ) {
    wxFileSystem::AddHandler( new wxZipFSHandler );
    wxXmlResource::Get()->InsertHandler( new wxToolBarAddOnXmlHandler );
    wxXmlResource::Get()->InitAllHandlers();
    xrcok = true;
  }
}

void Manager::LoadXRC( wxString relpath ) {
  LoadResource( relpath );
}

wxMenuBar *Manager::LoadMenuBar( wxString resid, bool createonfailure ) {
  wxMenuBar *m = wxXmlResource::Get()->LoadMenuBar( resid );
  if( !m && createonfailure ) {
    m = new wxMenuBar();
  }
  return m;
}

wxMenu *Manager::LoadMenu( wxString menu_id, bool createonfailure ) {
  wxMenu *m = wxXmlResource::Get()->LoadMenu( menu_id );
  if( !m && createonfailure ) {
    m = new wxMenu( _T( "" ) );
  }
  return m;
}

wxToolBar *Manager::LoadToolBar( wxFrame *parent, wxString resid, bool defaultsmall ) {
  if( !parent ) {
    return nullptr;
  }
  wxToolBar *tb = wxXmlResource::Get()->LoadToolBar( parent, resid );
  if( !tb ) {
    int flags = wxTB_HORIZONTAL;
    tb = parent->CreateToolBar( flags, wxID_ANY );
    tb->SetToolBitmapSize( wxSize( 16, 16 ) );
  }
  return tb;
}

wxToolBar* Manager::CreateEmptyToolbar() {
  wxSize size = wxSize( 16, 16 ) ;
  toolbar = new wxToolBar( GetAppFrame(), -1, wxDefaultPosition, size, wxTB_FLAT | wxTB_NODIVIDER );
  toolbar->SetToolBitmapSize( size );
  return toolbar;
}

wxToolBar* Manager::GetMinToolbar() {
  return toolbar;
}

void Manager::AddonToolBar( wxToolBar* toolBar, wxString resid ) {
  if( !toolBar ) {
    return;
  }
  wxXmlResource::Get()->LoadObject( toolBar, nullptr, resid, _T( "wxToolBarAddOn" ) );
}

wxFrame* Manager::GetAppFrame() const {
  return m_pAppWindow;
}

wxWindow* Manager::GetAppWindow() const {
  return ( wxWindow* )m_pAppWindow;
}

ProjectManager* Manager::GetProjectManager() const {
  return ProjectManager::Get();
}

EditorManager* Manager::GetEditorManager() const {
  return EditorManager::Get();
}

LogManager* Manager::GetLogManager() const {
  return LogManager::Get();
}

PluginManager* Manager::GetPluginManager() const {
  return PluginManager::Get();
}

ToolsManager* Manager::GetToolsManager() const {
  return ToolsManager::Get();
}

MacrosManager* Manager::GetMacrosManager() const {
  return MacrosManager::Get();
}

PersonalityManager* Manager::GetPersonalityManager() const {
  return PersonalityManager::Get();
}

UserVariableManager* Manager::GetUserVariableManager() const {
  return UserVariableManager::Get();
}

ScriptingManager* Manager::GetScriptingManager() const {
  return ScriptingManager::Get();
}

ConfigManager* Manager::GetConfigManager( const wxString& name_space ) const {
  return CfgMgrBldr::GetConfigManager( name_space );
}

FileManager* Manager::GetFileManager() const {
  return FileManager::Get();
}

DebuggerManager* Manager::GetDebuggerManager() const {
  return DebuggerManager::Get();
}

ColourManager* Manager::GetColourManager() const {
  return ColourManager::Get();
}

CCManager* Manager::GetCCManager() const {
  return CCManager::Get();
}

bool Manager::LoadResource( const wxString& file ) {
  wxString resourceFile = ConfigManager::LocateDataFile( file, sdDataGlobal | sdDataUser );
  wxString memoryFile = _T( "memory:" ) + file;
  if( wxFile::Access( resourceFile, wxFile::read ) == false ) {
    Get()->GetLogManager()->LogError( _T( "管理器访问XRC资源失败 ---  " ) + resourceFile );
    return false;
  }
  wxFile f( resourceFile, wxFile::read );
  char *buf = nullptr;
  try {
    size_t len = f.Length();
    buf = new char[len];
    f.Read( buf, len );
    wxMemoryFSHandler::AddFile( file, buf, len );
    if( !wxXmlResource::Get()->Load( memoryFile ) ) {
      Get()->GetLogManager()->LogError( _T( "管理器加载XRC资源失败 ---  " ) + resourceFile + _T( " ---  " )  + memoryFile );
    }
    delete[] buf;
    return true;
  } catch( ... ) {
    delete[] buf;
    Get()->GetLogManager()->LogError( _T( "管理器丢失XRC资源  ---  " ) + resourceFile );
    return false;
  }
}

wxCmdLineParser* Manager::GetCmdLineParser() {
  return &m_CmdLineParser;
}

void Manager::RegisterEventSink( wxEventType eventType, IEventFunctorBase<CodeBlocksEvent>* functor ) {
  m_EventSinks[eventType].push_back( functor );
}

void Manager::RegisterEventSink( wxEventType eventType, IEventFunctorBase<CodeBlocksDockEvent>* functor ) {
  m_DockEventSinks[eventType].push_back( functor );
}

void Manager::RegisterEventSink( wxEventType eventType, IEventFunctorBase<CodeBlocksLayoutEvent>* functor ) {
  m_LayoutEventSinks[eventType].push_back( functor );
}

void Manager::RegisterEventSink( wxEventType eventType, IEventFunctorBase<CodeBlocksLogEvent>* functor ) {
  m_LogEventSinks[eventType].push_back( functor );
}

void Manager::RemoveAllEventSinksFor( void* owner ) {
  for( EventSinksMap::iterator mit = m_EventSinks.begin(); mit != m_EventSinks.end(); ++mit ) {
    EventSinksArray::iterator it = mit->second.begin();
    bool endIsInvalid = false;
    while( !endIsInvalid && it != mit->second.end() ) {
      if( ( *it ) && ( *it )->GetThis() == owner ) {
        EventSinksArray::iterator it2 = it++;
        endIsInvalid = it == mit->second.end();
        delete( *it2 );
        mit->second.erase( it2 );
      } else
      { ++it; }
    }
  }
  for( DockEventSinksMap::iterator mit = m_DockEventSinks.begin(); mit != m_DockEventSinks.end(); ++mit ) {
    DockEventSinksArray::iterator it = mit->second.begin();
    bool endIsInvalid = false;
    while( !endIsInvalid && it != mit->second.end() ) {
      if( ( *it ) && ( *it )->GetThis() == owner ) {
        DockEventSinksArray::iterator it2 = it++;
        endIsInvalid = it == mit->second.end();
        delete( *it2 );
        mit->second.erase( it2 );
      } else
      { ++it; }
    }
  }
  for( LayoutEventSinksMap::iterator mit = m_LayoutEventSinks.begin(); mit != m_LayoutEventSinks.end(); ++mit ) {
    LayoutEventSinksArray::iterator it = mit->second.begin();
    bool endIsInvalid = false;
    while( !endIsInvalid && it != mit->second.end() ) {
      if( ( *it ) && ( *it )->GetThis() == owner ) {
        LayoutEventSinksArray::iterator it2 = it++;
        endIsInvalid = it == mit->second.end();
        delete( *it2 );
        mit->second.erase( it2 );
      } else
      { ++it; }
    }
  }
  for( LogEventSinksMap::iterator mit = m_LogEventSinks.begin(); mit != m_LogEventSinks.end(); ++mit ) {
    LogEventSinksArray::iterator it = mit->second.begin();
    bool endIsInvalid = false;
    while( !endIsInvalid && it != mit->second.end() ) {
      if( ( *it ) && ( *it )->GetThis() == owner ) {
        LogEventSinksArray::iterator it2 = it++;
        endIsInvalid = it == mit->second.end();
        delete( *it2 );
        mit->second.erase( it2 );
      } else
      { ++it; }
    }
  }
}
